from flask import Flask, render_template, request, redirect, url_for,send_from_directory,send_file
from flask import session,jsonify,Response
import pygame._sdl2 as sdl2
from pygame import mixer
import pygame.mixer
import keyboard
import threading
import datetime
import requests
import socket
import ollama
import random
import shutil
import wave
import json
import time
import os 
import re
import sounddevice as sd
import numpy as np
import time

app = Flask(__name__)

app.secret_key = ''

with open('config/配置文件/config.txt','r',encoding = 'utf-8') as f:
    data = f.readlines()
    
    live_config = {}

    for item in data:
        if not item.strip():
            continue
        
        live_config[item.split(':')[0]] = {
            'ip_address':item.split(':')[1].strip()
        }


# 平台列表
platforms = []

for platform in os.listdir(os.path.join('config','话术脚本')):
    if platform.startswith('.'):
        continue

    platforms.append(platform)

# 产品列表
products = []

for platform in os.listdir(os.path.join('config','话术脚本')):
    if platform.startswith('.'):
        continue

    for product in os.listdir(os.path.join('config','话术脚本',platform)):
        if product.startswith('.'):
            continue

        products.append(product)

# 音色列表
streamers = [streamer for streamer in os.listdir(os.path.join('D:\\','音色定制')) if os.path.isdir(os.path.join('D:\\','音色定制',streamer))]

task_config = {}

for scene in ['scene-1','scene-2','scene-3','scene-4','scene-5']:
    task_config[scene] = {
        'scene_name': scene,
        'current_product': '',
        'current_device': '',
        'current_streamer':'',
        'live_platform':'',
        'startPlayAudio': False,
        'pausePlayAudio':False,
        'startGetAudio': False,
        'audioPlaying':False,
        'humanSpeaking':False,
        'ip_address': '',
        'volume_adjust':'',
        'active': True if scene == 'scene-1' else False
    }


# 打印分割线
def print_split_line():
    width = os.get_terminal_size().columns
    text = '=' * width
    print(text)


# 监听真人说话的声音，超过某一个分贝
silence_time = 0

def record_audio(duration = 86400, fs = 44100, channels = 1):
    def callback(indata, frames, time, status):
        global silence_time,task_config
        
        volume = np.linalg.norm(indata) / frames
        
        if volume > 0.001:
            for scene in ['scene-1','scene-2','scene-3','scene-4','scene-5']:
                task_config[scene]['pausePlayAudio'] = True
                task_config[scene]['humanSpeaking'] = True

            silence_time = 0
        else:
            silence_time += 1

            if silence_time > 150:
                for scene in ['scene-1','scene-2','scene-3','scene-4','scene-5']:
                    task_config[scene]['pausePlayAudio'] = False
                    task_config[scene]['humanSpeaking'] = False

    with sd.InputStream(callback = callback, channels = channels, samplerate = fs):
        sd.sleep(duration * 1000)


def play_wav(file_path,scene_idx,mode):
    global task_config,image

    if not os.path.exists(file_path):
        return
    
    pygame.mixer.init(devicename = None if task_config[scene_idx]['current_device'] == '桌面音频' else task_config[scene_idx]['current_device'])

    try:
        pygame.mixer.music.load(file_path)

        if task_config[scene_idx]['volume_adjust']:
            pygame.mixer.music.set_volume(int(task_config[scene_idx]['volume_adjust']) / 100)

        pygame.mixer.music.play()

        while pygame.mixer.music.get_busy():
            task_config[scene_idx]['audioPlaying'] = True

            if not task_config[scene_idx]['startPlayAudio']:
                pygame.mixer.music.pause()
                break

            if task_config[scene_idx]['pausePlayAudio']:
                pygame.mixer.music.pause()
                break

        pygame.mixer.music.stop()
        pygame.mixer.music.unload()

    except:
        print(file_path,'**********无法播放**********')
    
    finally:
        os.remove(file_path)

    task_config[scene_idx]['audioPlaying'] = False


@app.route('/')
def login():
    return render_template('login.html')


@app.route('/index')
def index():
    mixer.init()
    devices = sdl2.audio.get_audio_device_names(False) + ['桌面音频']
    mixer.quit()

    return render_template('index.html', products = products,devices = devices,streamers = streamers,platforms = platforms)


# 开始播放音频
def startPlayAudioTask(scene_idx):
    global task_config

    for i in range(10000000):
        if not task_config[scene_idx]['startPlayAudio']:
            break

        files = sorted(os.listdir(os.path.join('config','话术音频',task_config[scene_idx]['live_platform'],task_config[scene_idx]['current_product'],task_config[scene_idx]['current_streamer'],'主播')))

        for file in files:
            if not task_config[scene_idx]['startPlayAudio']:
                break
            
            if task_config[scene_idx]['pausePlayAudio']:
                while True:
                    if not task_config[scene_idx]['pausePlayAudio']:
                        break

            if not file.endswith('.wav'):
                continue

            file_path = os.path.join('config','话术音频',task_config[scene_idx]['live_platform'],task_config[scene_idx]['current_product'],task_config[scene_idx]['current_streamer'],'主播',file)

            play_wav(file_path,scene_idx,'main')

            # 停顿随机变化，方便主播真人插话
            time.sleep(random.uniform(3,5))

        # 这里睡眠0.1秒是为了防止音频过少的时候for循环一下子循环完了
        time.sleep(0.1)

    print('startPlayAudioTask:执行结束')


# 开始播放音频
@app.route('/startPlayAudio',methods = ['POST'])
def startPlayAudio():
    global task_config

    scene_idx = request.form.get('scene_idx')

    task_config[scene_idx]['startPlayAudio'] = True

    task_thread = threading.Thread(target = startPlayAudioTask,args = (scene_idx,))
    task_thread.start()

    return jsonify({'success':True,'message':''})


# 停止直播
@app.route('/stopPlayAudio',methods = ['POST'])
def stopPlayAudio():
    global task_config

    scene_idx = request.form.get('scene_idx')

    task_config[scene_idx]['startPlayAudio'] = False

    return jsonify({'success':True,'message':'直播已暂停'})


# 进入真人插话模式
@app.route('/startInsertMode',methods = ['POST'])
def startInsertMode():
    global task_config

    scene_idx = request.form.get('scene_idx')

    task_config[scene_idx]['startInsertMode'] = True

    task_thread = threading.Thread(target = record_audio)
    task_thread.start()

    return jsonify({'success':True,'message':'已进入真人插话模式'})


# 清空音频
@app.route('/clearAudio',methods = ['POST'])
def clearAudio():
    global task_config

    scene_idx = request.form.get('scene_idx')

    if not task_config[scene_idx]['live_platform'] or not task_config[scene_idx]['current_product'] or not task_config[scene_idx]['current_streamer']:
        return jsonify({'success':True,'message':''})

    if os.path.exists(os.path.join('config','话术音频',task_config[scene_idx]['live_platform'],task_config[scene_idx]['current_product'],task_config[scene_idx]['current_streamer'],'主播')):
        for file in os.listdir(os.path.join('config','话术音频',task_config[scene_idx]['live_platform'],task_config[scene_idx]['current_product'],task_config[scene_idx]['current_streamer'],'主播')):
            os.remove(os.path.join('config','话术音频',task_config[scene_idx]['live_platform'],task_config[scene_idx]['current_product'],task_config[scene_idx]['current_streamer'],'主播',file))

    return jsonify({'success':True,'message':''})


# 选择产品
@app.route('/selectProduct',methods = ['POST'])
def selectProduct():
    global task_config

    scene_idx = request.form.get('scene_idx')
    current_product = request.form.get('product')

    task_config[scene_idx]['current_product'] = current_product

    return jsonify({'success':True,'message':'已切换到' + current_product})


# 选择音色
@app.route('/selectStreamer',methods = ['POST'])
def selectStreamer():
    global task_config,live_config

    scene_idx = request.form.get('scene_idx')
    current_streamer = request.form.get('streamer')

    task_config[scene_idx]['current_streamer'] = current_streamer

    ip_address = live_config.get(current_streamer,'').get('ip_address')

    
    return jsonify({'success':True,'message':'已切换到' + current_streamer,'ip_address' : ip_address})


# 选择平台
@app.route('/selectLivePlatform',methods = ['POST'])
def selectLivePlatform():
    global task_config

    scene_idx = request.form.get('scene_idx')

    live_platform = request.form.get('live_platform')

    task_config[scene_idx]['live_platform'] = live_platform

    return jsonify({'success':True,'message':'已切换到' + live_platform})


# 选择设备
@app.route('/selectDevice',methods = ['POST'])
def selectDevice():
    global task_config

    scene_idx = request.form.get('scene_idx')
    current_device = request.form.get('device')

    task_config[scene_idx]['current_device'] = current_device

    return jsonify({'success':True,'message':'已切换到' + current_device})


# 音量调整
@app.route('/selectVolumeAdjust',methods = ['POST'])
def selectVolumeAdjust():
    global task_config
    
    scene_idx = request.form.get('scene_idx')
    volume_adjust = request.form.get('volume_adjust')

    task_config[scene_idx]['volume_adjust'] = volume_adjust

    return jsonify({'success':True,'message':''})


# 选择场景
@app.route('/selectScene',methods = ['POST'])
def selectScene():
    global task_config

    scene_idx = request.form.get('scene_idx')
    
    task_config[scene_idx]['active'] = True


    return jsonify({'success':True,'message':''})


# 开始远程获取主音频
def startGetMainAudioTask(scene_idx):
    global task_config

    if not task_config[scene_idx]['ip_address']:
        return
    
    print(task_config[scene_idx])

    url = 'http://' + task_config[scene_idx]['ip_address'] + '/download_main_audio'

    if not os.path.exists(os.path.join('config','话术音频',task_config[scene_idx]['live_platform'])):
        os.mkdir(os.path.join('config','话术音频',task_config[scene_idx]['live_platform']))

    if not os.path.exists(os.path.join('config','话术音频',task_config[scene_idx]['live_platform'],task_config[scene_idx]['current_product'])):
        os.mkdir(os.path.join('config','话术音频',task_config[scene_idx]['live_platform'],task_config[scene_idx]['current_product']))

    if not os.path.exists(os.path.join('config','话术音频',task_config[scene_idx]['live_platform'],task_config[scene_idx]['current_product'],task_config[scene_idx]['current_streamer'])):
        os.mkdir(os.path.join('config','话术音频',task_config[scene_idx]['live_platform'],task_config[scene_idx]['current_product'],task_config[scene_idx]['current_streamer']))

    if not os.path.exists(os.path.join('config','话术音频',task_config[scene_idx]['live_platform'],task_config[scene_idx]['current_product'],task_config[scene_idx]['current_streamer'],'主播')):
        os.mkdir(os.path.join('config','话术音频',task_config[scene_idx]['live_platform'],task_config[scene_idx]['current_product'],task_config[scene_idx]['current_streamer'],'主播'))

    while True:
        if len(os.listdir(os.path.join('config','话术音频',task_config[scene_idx]['live_platform'],task_config[scene_idx]['current_product'],task_config[scene_idx]['current_streamer'],'主播'))) > 100:
            print('库存达到了100，休眠十分钟')
            time.sleep(60 * 10)
            continue

        # 如果暂停直播就退出循环
        if not task_config[scene_idx]['startGetAudio']:
            break
        
        try:
            response = requests.post(url,data = {
                'product':task_config[scene_idx]['current_product'],
                'streamer':task_config[scene_idx]['current_streamer'],
                'platform':task_config[scene_idx]['live_platform']
            })
        except:
            print(task_config[scene_idx]['live_platform'],task_config[scene_idx]['current_product'],task_config[scene_idx]['current_streamer'],'获取主音频网络请求错误',datetime.datetime.now().strftime("%Y_%m_%d_%H_%M_%S"))
            continue

        if response.status_code == 200:
            save_path = os.path.join('config','话术音频',task_config[scene_idx]['live_platform'],task_config[scene_idx]['current_product'],task_config[scene_idx]['current_streamer'],'主播','%s.wav' % datetime.datetime.now().strftime("%Y_%m_%d_%H_%M_%S"))

            with open(save_path, 'wb') as file:
                file.write(response.content)
            
        elif response.status_code == 404:
            print("主音频文件不存在！")

        else:
            print(f"下载失败，状态码: {response.status_code}")

        time.sleep(1)

    print(task_config[scene_idx]['live_platform'],task_config[scene_idx]['current_streamer'],task_config[scene_idx]['current_product'],'暂停获取主音频')



# 开始获取音频
@app.route('/startGetAudio',methods = ['POST'])
def startGetAudio():
    global task_config

    scene_idx = request.form.get('scene_idx')
    ip_address = request.form.get('ip_address')

    task_config[scene_idx]['startGetAudio'] = True
    task_config[scene_idx]['ip_address'] = ip_address
    
    print('开始向',ip_address,scene_idx,'获取音频')

    task_thread = threading.Thread(target = startGetMainAudioTask,args = (scene_idx,))
    task_thread.start()

    return jsonify({'success':True,'message':''})


# 同步配置信息
@app.route('/update_task_config',methods = ['POST'])
def update_task_config():
    global task_config

    return jsonify(task_config)


# 查询音频库存
@app.route('/getAudioCount',methods = ['POST'])
def getAudioCount():
    global task_config,reply_sents_map

    scene_idx = request.form.get('scene_idx')

    if not task_config[scene_idx]['live_platform']:
        return jsonify({'success':True,'count': -1})

    if not task_config[scene_idx]['current_product']:
        return jsonify({'success':True,'count': -1})

    if not task_config[scene_idx]['current_streamer']:
        return jsonify({'success':True,'count': -1})
    
    if not os.path.exists(os.path.join('config','话术音频',task_config[scene_idx]['live_platform'])):
        return jsonify({'success':True,'count': -1})

    if not os.path.exists(os.path.join('config','话术音频',task_config[scene_idx]['live_platform'],task_config[scene_idx]['current_product'])):
        return jsonify({'success':True,'count': -1})

    if not os.path.exists(os.path.join('config','话术音频',task_config[scene_idx]['live_platform'],task_config[scene_idx]['current_product'],task_config[scene_idx]['current_streamer'])):
        return jsonify({'success':True,'count': -1})

    if not os.path.exists(os.path.join('config','话术音频',task_config[scene_idx]['live_platform'],task_config[scene_idx]['current_product'],task_config[scene_idx]['current_streamer'],'主播')):
        return jsonify({'success':True,'count': -1})

    data = [file for file in os.listdir(os.path.join('config','话术音频',task_config[scene_idx]['live_platform'],task_config[scene_idx]['current_product'],task_config[scene_idx]['current_streamer'],'主播')) if file.endswith('.WAV') or file.endswith('.wav')]

    return jsonify({'success':True,'count':len(data)})


# 查询是否正在播放音频
@app.route('/audioPlayingChecking',methods = ['POST'])
def audioPlayingChecking():
    global task_config

    scene_idx = request.form.get('scene_idx')

    return jsonify({'success':True,'audioPlaying':task_config[scene_idx]['audioPlaying'],'humanSpeaking':task_config[scene]['humanSpeaking']})


# 查询是否正在暂停播放音频
@app.route('/pausePlayingChecking',methods = ['POST'])
def pausePlayingChecking():
    global task_config

    scene_idx = request.form.get('scene_idx')

    return jsonify({'success':True,'flag':task_config[scene_idx]['pausePlayAudio']})


if __name__ == '__main__':
    app.run(debug = True,port = 6868,host = '0.0.0.0')
